<?php

namespace Sharks\Core\Http\Routing;

use InvalidArgumentException;
use Sharks\Core\AppContext;
use Sharks\Core\Cfg\AppConfig;
use Sharks\Core\Exception\RouteResolveException;
use Sharks\Core\Http\Request;
use Sharks\Core\Support\Bag\ParameterBag;
use Sharks\Core\Support\Base\Precondition;
use Sharks\Core\Support\Storage\ArrayLoader;

/**
 * Route表
 */
class RouteControl {

	const ROUTE_METHOD = array(
		Request::METHOD_GET,
		Request::METHOD_CONNECT,
		Request::METHOD_DELETE,
		Request::METHOD_HEAD,
		Request::METHOD_OPTIONS,
		Request::METHOD_PATCH,
		Request::METHOD_POST,
		Request::METHOD_PURGE,
		Request::METHOD_PUT,
		Request::METHOD_TRACE
	);

	private static $middlewareCollection = null;
	private static $namespace = null;
	private static $routeCollection = null;
	
	/**
	 * 静态方法调用, 满足 Route_method中的方法
	 * @param $name
	 * @param $arguments
	 * @throws RouteResolveException
	 */
	public static function __callStatic($name, $arguments) {
		if (!in_array(strtoupper($name), self::ROUTE_METHOD)) {
			throw new RouteResolveException('没有指定的Http方法');
		}

		$size = count($arguments);

		// if (3 < $size )
		// 	throw new RouteResolveException('Route方法调用参数数目不对');

		// if (!is_string($arguments[0]))
		// 	throw new RouteResolveException('Route方法第一个参数类型不对,应该为string');

		// if (!is_string($arguments[1]))
		// 	throw new RouteResolveException('Route方法第二个参数类型不对,应该为string');

		// if (3 == $size && !is_array($arguments[2]))
		// 	throw new RouteResolveException('Route方法第三个参数类型不对,应该为array');

		if (2 == $size) {
			self::addRoute($name, $arguments[0], $arguments[1]);
		}
		elseif (3 == $size) {
			self::addRoute($name, $arguments[0], $arguments[1], $arguments[2]);
		}
	}

    /**
     * 匹配任意Http方法
     * @param string $route
     * @param string $action
     * @param array $middlewares
     */
	public static function any($route, $action, array $middlewares = array()) {
		self::match(self::ROUTE_METHOD, $route, $action, $middlewares);
	}

    /**
     * 匹配相应的Http方法
     * @param array $methods
     * @param string $route
     * @param string $action
     * @param array $middlewares
     * @throws RouteResolveException
     */
	public static function match(array $verbs, $route, $action, array $middlewares = array()) {
		foreach ($verbs as $verb) {
			self::addRoute($verb, $route, $action, $middlewares, $desc);
		}
	}

	/**
	 * 统一前辍
	 * @param $namespace
	 * @param $callback
	 */
	public static function group($namespace, $callback) {
		self::$namespace = $namespace;
		$callback();
		self::$namespace = null;
	}

	/**
	 * 注册中间件
	 * @param [type] $name  [description]
	 * @param [type] $class [description]
	 * @param [type] $desc  [description]
	 */
	public static function addMiddleware($name, $class, $desc = null) {
		self::$middlewareCollection->register($name, $class, $desc);
	}

	/**
	 * 增加映射route
	 * @param [type] $verb         [description]
	 * @param [type] $newRoute     [description]
	 * @param [type] $oldRoute     [description]
	 * @param array  $mapParameter [description]
	 * @param [type] $desc         [description]
	 */
	public static function addRouteMap($verb, $newRoute, $oldRoute, array $mapParameter = array(), $desc = null) {
		self::$routeCollection->registerMap($verb, (is_null(self::$namespace) ? '' : self::$namespace ) . $newRoute, $oldRoute, $paramsMap, $desc);
	}

	/**
	 * 增加route
	 * @param [type] $verb        [description]
	 * @param [type] $route       [description]
	 * @param [type] $action      [description]
	 * @param array  $middlewares [description]
	 * @param [type] $desc        [description]
	 */
	public static function addRoute($verb, $route, $action, array $middlewares = array(), $desc = null) {
		self::$routeCollection->register($verb, (is_null(self::$namespace) ? '' : self::$namespace ) . $route, $action, $middlewares, $desc);
	}

	/**
	 * 增加route集合
	 * @param RouteCollection $routeCollection [description]
	 */
	public static function addRouteCollection(RouteCollection $routeCollection) {
		if (is_null(self::$routeCollection)) {
			self::$routeCollection = new RouteCollection;
		}
		self::$routeCollection->merge($routeCollection);
	}

	/**
	 * 增加中间件集合
	 * @param MiddlewareCollection $middlewareCollection [description]
	 */
	public static function addMiddlewareCollection(MiddlewareCollection $middlewareCollection) {
		if (is_null(self::$middlewareCollection)) {
			self::$middlewareCollection = new middlewareCollection;
		}
		self::$middlewareCollection->merge($middlewareCollection);
	}

	/**
	 * 获取中间件集合
	 * @return array
	 */
	public static function middlewares() {
		Precondition::checkNotNull(self::$middlewareCollection, 'Route未正确初始化, $middlewares为NULL');
		return self::$middlewareCollection->all();
	}

	public static function getMiddleware($name) {
		return self::$middlewareCollection->get($name)['class'];
	}

	/**
	 * 获取路由表
	 * @return array
	 */
	public static function routes() {
		if (is_null(self::$routeCollection)) {
			return null;
		}
		return self::$routeCollection->all();
	}

	/**
	 * URL构造
	 * @param string $action
	 * @param array $params
	 * @param array $query
	 * @param string $hash
	 */
	public static function url($action, array $params = array(), array $query = array(), $hash = null) {
		
		$routeMap = self::$routeCollection->reverse($action);
		
		$route = $routeMap['route'];
    	if (isset($routeMap['parameters'])) {//有参数
    		$route = $routeMap['route'];
    		foreach ($routeMap['parameters'] as $p) {
    		    if (!isset($params[$p])) {
    		        throw new InvalidArgumentException("构造[{$action}]的route时，需要参数[{$p}]没有指定");
                }
    			$route = str_replace('{'. $p .'}', $params[$p], $route);
                unset($params[$p]);//使用后删除对应的参数
    		}
    	}

    	$query = array_merge($query, $params);//可以使用$params中未使用的值来构造querystring
    	if (!empty($query)) {
    		$route .= '?' . http_build_query($query);
    	}
    	if (!is_null($hash)) {
    		$route .= '#' . $hash;
    	}
    	return $route;

	}
}